import 'dart:async';
import 'dart:typed_data';

import 'package:dartx/src/map.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:get/get.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:realm/realm.dart';
import 'package:sgy_flutter/api_service.dart';
import 'package:sgy_flutter/ble/HardwareVersion.dart';
import 'package:sgy_flutter/ble/battery_service.dart';
import 'package:sgy_flutter/ble/custom_service.dart';
import 'package:sgy_flutter/ble/device_info_service.dart';
import 'package:sgy_flutter/ble/old_service.dart';
import 'package:sgy_flutter/ble/relay_stream_controller.dart';
import 'package:sgy_flutter/database/device_entity.dart';
import 'package:sgy_flutter/extensions/get.dart';
import 'package:sgy_flutter/model/abnormal_zero_record.dart';
import 'package:sgy_flutter/model/detection_result_model.dart';
import 'package:sgy_flutter/model/device_info.dart';
import 'package:sgy_flutter/model/device_model.dart';
import 'package:sgy_flutter/model/device_type.dart';
import 'package:sgy_flutter/model/dfu_info_model.dart';
import 'package:sgy_flutter/model/dls_upload_model.dart';
import 'package:sgy_flutter/model/dls_upload_model_old.dart';
import 'package:sgy_flutter/model/ota_info_model.dart';
import 'package:sgy_flutter/model/pair_state.dart';
import 'package:sgy_flutter/model/product_type.dart';
import 'package:sgy_flutter/model/update_info.dart';
import 'package:sgy_flutter/widget/app_dialog.dart';

import 'base_ble_manager.dart';
import 'cycling_power_service.dart';
import 'package:loader_overlay/loader_overlay.dart';

import 'cycling_power_service_16.dart';
import 'icustom_service.dart';
import 'name_service.dart';

class BleManager extends BaseBleManager implements ICustomService {
  CyclingPowerService cyclingPowerService = CyclingPowerService();
  CyclingPowerService16 cyclingPowerService16 = CyclingPowerService16();

  DeviceInfoService deviceInfoService = DeviceInfoService();

  BatteryService batteryService = BatteryService();

  CustomService customService = CustomService();

  OldService oldService = OldService();

  NameService nameService = NameService();

  Rxn<num> rssi = Rxn();
  Rxn<num> battery = Rxn();
  Rxn<DeviceInfo> deviceInfo = Rxn();
  Rxn<int> powerOffset = Rxn();

  Timer? _rssiTimer;

  var hasNewFirmware = false.obs;

  @override
  void beforeConnect() {
    baseServices.clear();
    if (deviceModel?.isAxo == true) {
      //新版AXO有
      baseServices.add(cyclingPowerService);
      baseServices.add(cyclingPowerService16);
    }
    if (deviceModel?.isDls == true) {
      if (!HardwareVersion.DLS_1_0.sameVersion(deviceModel)) {
        // baseServices.add(cyclingPowerService16);
      }
    }
    if (deviceModel?.deviceType == DeviceType.axpower) {
      baseServices.add(cyclingPowerService);
      baseServices.add(cyclingPowerService16);
    }
    if (deviceModel?.deviceType == DeviceType.axocc) {
      baseServices.add(cyclingPowerService);
      baseServices.add(cyclingPowerService16);
    }
    baseServices.add(deviceInfoService);
    baseServices.add(batteryService);
    baseServices.add(customService);
    baseServices.add(oldService);
    baseServices.add(nameService);
    super.beforeConnect();
  }

  @override
  FutureOr onDeviceConnected() async {}

  /**
   * 进去页面就去获取数据
   */
  Future enterPage() async {
    try {
      printInfo(info: "${runtimeType} enterPage");
      try {
        await openDataUpload();
      } catch (e) {
        printError(info: "openDataUpload:$e");
      }

      _rssiTimer?.cancel();
      final rssi = await device?.readRssi();
      this.rssi(rssi);

      _rssiTimer = Timer.periodic(const Duration(seconds: 5), (_) async {
        printInfo(info: "${runtimeType} readRSSI");
        final rssi = await device?.readRssi();
        this.rssi(rssi);
      });
      final battery = await batteryService.readBattery();
      this.battery(battery);

      final deviceInfo = await deviceInfoService.readDeviceInfo();
      this.deviceInfo(deviceInfo);
      _updateDeviceInfo(deviceInfo);

      this.powerOffset(await getScaleFactor());
      await checkDfu();
      printInfo(info: "enterPage Success");
    } catch (e) {
      printError(info: "$e");
    }
  }

  /**
   * 只有当硬件版本没有的时候才会去更新，固件版本请在里面去获取
   */
  Future _updateDeviceInfo(DeviceInfo deviceInfo) async {
    if (deviceModel != null) {
      final model = deviceModel!;
      Realm realm = Get.find();
      final entity = await realm
          .all<RealmDeviceEntity>()
          .query("address == '${model.address}'")
          .changes
          .first;
      if (entity.results.isNotEmpty && (model.hardware == null || model.hardware?.isEmpty == true)) {
        model.hardware = deviceInfo.hardwareRevision;
        model.firmware = deviceInfo.firmwareRevision;
        final saveEntity = model.toEntity(id: entity.results.first.id);
        realm.writeAsync(() {
          realm.add(saveEntity, update: true);
        });
      }
    }
  }

  @override
  Future cleanService() {
    _rssiTimer?.cancel();
    rssi.value = (null);
    battery.value = null;
    deviceInfo.value = null;
    powerOffset.value = null;
    hasNewFirmware(false);
    printInfo(info: "${runtimeType} cleanService");
    return super.cleanService();
  }

  void refreshPowerOffset() async {
    try {
      var powerOffset = (await getScaleFactor()) ?? 0;
      this.powerOffset(powerOffset);
    } catch (e) {
      printError(info: "$e");
    }
  }

  @override
  void onClose() {
    if (deviceModel != null) {
      disconnect(deviceModel!);
    }
    cleanService();
    super.onClose();
  }

  @override
  Future<PairState> getPairState() {
    return customService.getPairState();
  }

  /**
   * 仅DLS_L有效
   */
  @override
  Future<bool> startPair() {
    return customService.startPair();
  }

  @override
  Future<Uint8List> adjustZero() async {
    switch (deviceModel?.productType) {
      case ProductType.dls:
        return await customService.adjustZero();
      case ProductType.apm2:
      case ProductType.axpower:
      case ProductType.axocc:
      case ProductType.hiflow:
      case ProductType.jt:
      case ProductType.axo:
        return await customService.adjustZero();

      case ProductType.unknow:
      case null:
        throw AssertionError("adjustZero 未实现");
    }
  }

  @override
  Future<DetectionResultModel> detection() async {
    switch (deviceModel?.productType) {
      case ProductType.dls:
        return await customService.detection();
      case ProductType.apm2:
      case ProductType.axpower:
      case ProductType.axocc:
      case ProductType.hiflow:
      case ProductType.jt:
      case ProductType.axo:
        return await customService.detection();

      case ProductType.unknow:
      case null:
        throw AssertionError("detection 未实现");
    }
  }

  @override
  Future<AbnormalZeroRecord> fetchAbnormalZeroRecord() async {
    switch (deviceModel?.productType) {
      case ProductType.dls:
        return await customService.fetchAbnormalZeroRecord();
      case ProductType.apm2:
      case ProductType.axpower:
      case ProductType.axocc:
      case ProductType.hiflow:
      case ProductType.jt:
      case ProductType.axo:
        return await customService.fetchAbnormalZeroRecord();

      case ProductType.unknow:
      case null:
        throw AssertionError("fetchAbnormalZeroRecord 未实现");
    }
  }

  @override
  Future<List<Pair<int, String>>> fetchAdjustZeroRecord() async {
    switch (deviceModel?.productType) {
      case ProductType.dls:
        return await customService.fetchAdjustZeroRecord();
      case ProductType.axo:
        return await customService.fetchAdjustZeroRecord();
      case ProductType.apm2:
        return await customService.fetchAdjustZeroRecord();
      case ProductType.axpower:
        return await customService.fetchAdjustZeroRecord();
      case ProductType.axocc:
        return await customService.fetchAdjustZeroRecord();
      case ProductType.hiflow:
        return await customService.fetchAdjustZeroRecord();
      case ProductType.jt:
      case ProductType.unknow:
      case null:
        throw AssertionError("fetchAdjustZeroRecord 未实现");
    }
  }

  @override
  Future<OTAInfoModel> getFallbackVersion() async {
    switch (deviceModel?.productType) {
      case ProductType.dls:
        return await customService.getFallbackVersion();
      case ProductType.apm2:
      case ProductType.axpower:
      case ProductType.axocc:
      case ProductType.hiflow:
      case ProductType.axo:
        return await customService.getFallbackVersion();

      case ProductType.jt:
      case ProductType.unknow:
      case null:
        throw AssertionError("getFallbackVersion 未实现");
    }
  }

  /**
   * AXO 专有
   */
  @override
  Future<bool> getReverseChain2Zero() async {
    switch (deviceModel?.productType) {
      case ProductType.axo:
        return await customService.getReverseChain2Zero();
      case ProductType.dls:
      case ProductType.apm2:
      case ProductType.axpower:
      case ProductType.axocc:
      case ProductType.hiflow:
      case ProductType.jt:
      case ProductType.unknow:
      case null:
        throw AssertionError("getReverseChain2Zero 未实现");
    }
  }

  @override
  Future<int?> getScaleFactor() async {
    switch (deviceModel?.productType) {
      case ProductType.dls:
        return await customService.getScaleFactor();
      case ProductType.apm2:
      case ProductType.axpower:
      case ProductType.axocc:
      case ProductType.hiflow:
      case ProductType.axo:
        return await customService.getScaleFactor();

      case ProductType.jt:
      case ProductType.unknow:
      case null:
        throw AssertionError("getScaleFactor未实现");
    }
  }

  @override
  Future<bool> isCharging() async {
    switch (deviceModel?.productType) {
      case ProductType.dls:
        if (deviceModel != null && HardwareVersion.isOldDevice(deviceModel)) {
          return customService.writeCharacteristic == null;
        }
        return await customService.isCharging();

      case ProductType.axo:
        printInfo(info: "isOldDevice:${HardwareVersion.isOldDevice(deviceModel)},'${deviceModel?.hardware}'");
        if (deviceModel != null && HardwareVersion.isOldDevice(deviceModel)) {
          return customService.writeCharacteristic == null;
        }
        return await customService.isCharging();
      case ProductType.apm2:
      case ProductType.axpower:
      case ProductType.axocc:
        if (deviceModel != null && HardwareVersion.isOldDevice(deviceModel)) {
          return customService.writeCharacteristic == null;
        } else {
          return false;
        }
      case ProductType.hiflow:
      case ProductType.jt:
      case ProductType.unknow:
        return false;
      case null:
        throw AssertionError("isCharging 未实现");
    }
  }

  @override
  Future openDataUpload() async {
    printInfo(info: 'openDataUpload');
    switch (deviceModel?.productType) {
      case ProductType.dls:
        return await customService.openDataUpload();
      case ProductType.axo:
        return;
      case ProductType.apm2:
      case ProductType.axpower:
      case ProductType.axocc:
      case ProductType.hiflow:
      case ProductType.jt:
        return;
      case ProductType.unknow:
      case null:
        throw AssertionError("openDataUpload 未实现");
    }
  }

  @override
  Future<bool> openTransportMode() async {
    switch (deviceModel?.productType) {
      case ProductType.dls:
        return await customService.openTransportMode();
      case ProductType.axo:
        return await customService.openTransportMode();
      case ProductType.apm2:
      case ProductType.axpower:
      case ProductType.axocc:
      case ProductType.hiflow:
      case ProductType.jt:
      case ProductType.unknow:
      case null:
        throw AssertionError("openTransportMode 未实现");
    }
  }

  @override
  Future<Uint8List> resetPowerOffset() async {
    switch (deviceModel?.productType) {
      case ProductType.dls:
        return await customService.resetPowerOffset();
      case ProductType.apm2:
      case ProductType.axpower:
      case ProductType.axocc:
      case ProductType.hiflow:
      case ProductType.jt:
      case ProductType.axo:
        return await customService.resetPowerOffset();

      case ProductType.unknow:
      case null:
        throw AssertionError("resetPowerOffset 未实现");
    }
  }

  @override
  Future<bool> setPowerOffset(int value) async {
    switch (deviceModel?.productType) {
      case ProductType.dls:
        return await customService.setPowerOffset(value);
      case ProductType.apm2:
      case ProductType.axpower:
      case ProductType.axocc:
      case ProductType.hiflow:
      case ProductType.jt:
      case ProductType.axo:
        return await customService.setPowerOffset(value);

      case ProductType.unknow:
      case null:
        throw AssertionError("setPowerOffset 未实现");
    }
  }

  @override
  Future<bool> setReverseChain2Zero(bool enable) async {
    switch (deviceModel?.productType) {
      case ProductType.dls:
        return await customService.setReverseChain2Zero(enable);
      case ProductType.apm2:
      case ProductType.axpower:
      case ProductType.axocc:
      case ProductType.hiflow:
      case ProductType.jt:
      case ProductType.axo:
        return await customService.setReverseChain2Zero(enable);

      case ProductType.unknow:
      case null:
        throw AssertionError("setReverseChain2Zero 未实现");
    }
  }

  @override
  Stream<DlsUploadModel> get dlsUploadModel => customService.dlsUploadModel;

  @override
  Future<int> getSensorType() {
    return customService.getSensorType();
  }

  @override
  Future<bool> setSensorType(int type) {
    return customService.setSensorType(type);
  }

  @override
  Stream<DlsUploadModelOld> get dlsUploadDataOld =>
      customService.dlsUploadDataOld;

  @override
  Future<DfuInfoModel> checkDfu() async {
    final ApiService apiService = Get.find();
    final deviceInfo = await deviceInfoService.readDeviceInfo();
    UpdateInfoModel? updateInfoModel;
    try {
      if (deviceInfo.hardwareRevision == HardwareVersion.DLS_1_0.value) {
        final resp = await apiService.getFirmwareVersion(
          deviceInfo.hardwareRevision ?? "",
        );
        if (resp.data != null) {
          updateInfoModel = resp.data!;
        }
      } else if (deviceInfo.hardwareRevision
              ?.startsWith(HardwareVersion.JT_1_0.value) ==
          true) {
        final resp = await apiService.getFirmwareVersion(
          deviceInfo.hardwareRevision ?? '',
        );
        if (resp.data != null) {
          updateInfoModel = resp.data!;
        }
      } else if (deviceInfo.hardwareRevision
              ?.startsWith(HardwareVersion.AXO_2_0.value) ==
          true) {
        // AXO 硬件版本PM开头
        final resp = await apiService.getFirmwareVersionOld(
            newVersion: true,
            deviceType: _deviceType(deviceModel),
            firmwareVersion: deviceInfo.firmwareRevision ?? "");
        if (resp.data != null) {
          updateInfoModel = resp.data!;
        }
      } else {
        final resp = await apiService.getFirmwareVersionOld(
            newVersion: false,
            deviceType: _deviceType(deviceModel),
            firmwareVersion: deviceInfo.firmwareRevision ?? "");
        if (resp.data != null) {
          updateInfoModel = resp.data!;
        }
      }
    } catch (e) {}
    hasNewFirmware(updateInfoModel?.version != null &&
        updateInfoModel?.version != deviceInfo.firmwareRevision);
    return DfuInfoModel(deviceInfo: deviceInfo, updateInfo: updateInfoModel);
  }

  // 给旧的服务器接口用的
  String _deviceType(DeviceModel? model) {
    final name = model?.name ?? '';
    // AXO 硬件版本PM开头
    var type = "";
    if (name.contains("AXOCC") || name.contains("AXOcc")) {
      type = "AXOcc";
    } else if (name.contains("AXO") || name.contains("SPM2")) {
      type = "AXO";
    } else if (name.contains("DLS_L")) {
      type = "DLS_L";
    } else if (name.contains("DLS_R")) {
      type = "DLS_R";
    } else if (name.contains("AXPOWER")) {
      type = "AXPOWER";
    } else if (name.contains("HIFLOW")) {
      type = "HIFLOW";
    }
    return type;
  }
}
